﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DimOS.Constants;
using DimOS.DimSH;
using String = DimOS.Plugs.String;

namespace DimOS.Internals
{
    public class Token
    {
        public TokenType Type { get; private set; }

        public string Value { get; private set; }

        public int Priority { get; private set; }

        public bool CustomMatcher { get; private set; }

        public int StartPosition { get; private set; }

        public int EndPosition { get; private set; }

        public Token(TokenType type, string value = "", int priority = -1, 
            bool customMatcher = false, int startPosition = -1, int endPosition = -1)
        {
            Type = type;
            Value = value;
            Priority = priority;
            CustomMatcher = customMatcher;
            StartPosition = startPosition;
            EndPosition = endPosition;
        }

        public static List<Token> Find(string source, Token token)
        {
            if (!token.CustomMatcher)
            {
                var pos = String.IndexOf(source, token.Value);
                var matches = new List<Token>(); var temp = 0;
                while (pos != -1)
                {
                    matches.Add(new Token(token.Type, token.Value, token.Priority,
                    false, pos + temp, pos + temp + token.Value.Length));

                    source = source.Remove(0, pos + token.Value.Length);
                    temp += pos + token.Value.Length;
                    pos = String.IndexOf(source, token.Value);
                } return matches;
            }

            if (token.Type == TokenType.VerbatimString)
            {
                var start = -1;
                if (source[0] == Tokens.VerbatimString) start = 0; else for (int i = 1; i < 
                source.Length; i++) if ((source[i] == Tokens.VerbatimString) && (source[i - 1] !=
                Tokens.MirrorLeft && source[i - 1] != Tokens.MirrorRight)) { start = i; break; }

                var matches = new List<Token>(); if (start == -1) return matches;
                matches.Add(new Token(token.Type, "", token.Priority, true, start));
                var trigger = true; for (int i = start + 1; i < source.Length; i++)
                {
                    if ((source[i] == Tokens.VerbatimString) && (source[i - 1] != Tokens
                    .MirrorLeft && source[i - 1] != Tokens.MirrorRight)) { if (trigger)
                    matches[matches.Count - 1].EndPosition = i + 1; else matches.Add(new
                    Token(token.Type, "", token.Priority, true, i)); trigger = !trigger; }
                    else if (trigger) matches[matches.Count - 1].Value += source[i];
                } if (trigger) matches[matches.Count - 1].EndPosition = source.Length;
                return matches;
            }


            //if (token.Type == TokenType.HereString)
            //{
            //    var start = -1;
            //    if (source[0] == Tokens.HereStringLeft || source[0] == Tokens.HereStringRight)
            //    start = 0; else for (int i = 1; i < source.Length; i++) if ((source[i] == Tokens
            //    .HereStringLeft || source[i] == Tokens.HereStringRight) && (source[i - 1] !=
            //    Tokens.MirrorLeft && source[i - 1] != Tokens.MirrorRight)) { start = i; break; }

            //    var matches = new List<Token>(); if (start == -1) return matches;
            //    matches.Add(new Token(token.Type, "", token.Priority, true, start));
            //    var trigger = true; //Indicate that the here document was started

            //    for (int i = start + 1; i < source.Length; i++)
            //    {
            //        if ((source[i] == Tokens.HereStringLeft || source[i] == Tokens.HereStringRight)
            //        && (source[i - 1] != Tokens.MirrorLeft && source[i - 1] != Tokens.MirrorRight))
            //        { if (trigger) matches[matches.Count - 1].EndPosition = i + 1; else matches.Add
            //        (new Token(token.Type, "", token.Priority, true, i)); trigger = !trigger; }
            //        else if (trigger) matches[matches.Count - 1].Value += source[i];
            //    }
            //    if (trigger) matches[matches.Count - 1].EndPosition = source.Length;
            //    return matches;
            //}
            if (token.Type == TokenType.Path)
            {
                var matches = new List<Token>();
                var match = false; var value = false; 
                for (int i = 0; i < source.Length; i++)
                {
                    if (source[i] == Tokens.ValueLeft) value = true;
                    else if (source[i] == Tokens.ValueRight) value = false;

                    if ((source[i] == Separators.PathDelimiter ||
                        source[i] == Separators.IndicatorRoot ||
                        source[i] == Separators.IndicatorUser ||
                        source[i] == Separators.PathTemp) && !match)
                        { match = true; matches.Add(new Token(token
                        .Type, "", token.Priority, true, i)); } else if
                        (match) for (int j = 0; j < Tokens.List.Count;
                        j++) if (!value && source[i].ToString() ==
                        Tokens.List[j].Value && !Tokens.List[j]
                        .CustomMatcher) { match = false; matches 
                        [matches.Count - 1].EndPosition = i; break; }

                    if (match) { matches[matches.Count - 1].Value += source[i];}
                } if (match) matches[matches.Count - 1].EndPosition = source.Length;
                return matches;
            }
            //if (token.Type == TokenType.Command)
            //{
            //    while ()
            //}

            return new List<Token>();
        }

        public static List<Token> Find(string source)
        {
            var list = new List<Token>();
            for (int i = 0; i < Tokens.List.Count; i++)
            {
                var temp = Find(source, Tokens.List[i]);
                for (int j = 0; j < temp.Count; j++)
                    list.Add(temp[j]);
            } return list;
        }
    }
}
